<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="异常处理">
<meta name="twitter:description" content="<p>异常处理(try)：万能异常捕获；主动抛出异常(raise)：自定义异常，内置异常类型；断言(assert);traceback模块:将异常信息保存到文件</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/python-exception-handling.html"/>
<meta property="og:title" content="来玩魔王的咚 | 异常处理" />
<meta property="og:description" content="<p>异常处理(try)：万能异常捕获；主动抛出异常(raise)：自定义异常，内置异常类型；断言(assert);traceback模块:将异常信息保存到文件</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>异常处理(try)：万能异常捕获；主动抛出异常(raise)：自定义异常，内置异常类型；断言(assert);traceback模块:将异常信息保存到文件</p>" />

    <meta name="tags" content="异常处理" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li class="active"><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-09-15 12:00:00+08:00">
                <script>document.write(moment('2020-09-15 12:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-09-15 12:00:00+08:00">
                <script>document.write(moment('2020-09-15 16:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            异常处理
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#yi-chang-chu-li-try">异常处理(try)</a><ul>
<li><a href="#jian-dan-de-jie-gou">简单的结构</a></li>
<li><a href="#duo-ge-yi-chang">多个异常</a></li>
<li><a href="#wan-neng-yi-chang-bu-huo">万能异常捕获</a></li>
<li><a href="#else-dai-ma-kuai">else代码块</a></li>
<li><a href="#finally-dai-ma-kuai">finally代码块</a></li>
<li><a href="#xiao-jie">小结</a></li>
</ul>
</li>
<li><a href="#zhu-dong-pao-chu-yi-chang-raise">主动抛出异常(raise)</a><ul>
<li><a href="#zi-ding-yi-yi-chang">自定义异常</a></li>
<li><a href="#nei-zhi-yi-chang-lei-xing">内置异常类型</a></li>
</ul>
</li>
<li><a href="#duan-yan-assert">断言(assert)</a></li>
<li><a href="#traceback-mo-kuai">traceback模块</a><ul>
<li><a href="#jiang-yi-chang-xin-xi-bao-cun-dao-wen-jian">将异常信息保存到文件</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="yi-chang-chu-li-try"><a class="toclink" href="#yi-chang-chu-li-try">异常处理(try)</a></h3>
<p>在编程过程中为了增加友好性，在程序出现bug时一般不会将错误信息显示给用户，而是现实一个提示的页面。  </p>
<h4 id="jian-dan-de-jie-gou"><a class="toclink" href="#jian-dan-de-jie-gou">简单的结构</a></h4>
<p>这里没有给a变量赋值，所以a变量是不存在的。运行后抛出错误如下:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s2">&quot;&lt;pyshell#0&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="ne">NameError</span><span class="p">:</span> <span class="n">name</span> <span class="s1">&#39;a&#39;</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">defined</span>
<span class="o">&gt;&gt;&gt;</span> 
</code></pre></div>

<p>我们可以把可能出现异常的语句放到下面的try里：</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">try</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">NameError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;变量名不存在 </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>


<span class="n">变量名不存在</span> <span class="n">name</span> <span class="s1">&#39;a&#39;</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">defined</span>
<span class="o">&gt;&gt;&gt;</span> 
</code></pre></div>

<p>关键字as，前面是异常种类，后面是错误的信息，对应上个例子中报错最后一行冒号前后的内容。  </p>
<p>也可以写多个except来处理不同的异常类型。如果多个异常类型可以使用相同的出场方法，那么看下面的例子。  </p>
<h4 id="duo-ge-yi-chang"><a class="toclink" href="#duo-ge-yi-chang">多个异常</a></h4>
<p>再加一个错误，让except同时处理多个异常类型：</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># 这个元祖只有第0项，我想在要取第1项,会报错</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>  <span class="c1"># 上面已经捕获到异常了，try中后面的代码就不会再执行了，而是跳去执行except了</span>
<span class="k">except</span> <span class="ne">NameError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;变量名不存在：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">IndexError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;索引错误：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<p>这次代码块中会有两种不同的错误类型。捕获到异常后，直接就去找except。如果错误类型不在except里，仍然会抛出错误。如果错误类型符合，就执行这个except代码块内的代码，然后跳出整个try代码块继续往后执行。  </p>
<p>还可以这样，把几种异常种类写一起：</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># 把这行改正确，触发出下一行的错误</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">NameError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;变量名或索引错误：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<h4 id="wan-neng-yi-chang-bu-huo"><a class="toclink" href="#wan-neng-yi-chang-bu-huo">万能异常捕获</a></h4>
<p>我们还可以使用Exception这个错误类型（也可以缺省错误类型），捕获所有的错误：</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>  <span class="c1"># 这里也可以只写`except :`直接换行，但是无法获取到错误信息e</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;捕获到异常：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<p>虽然什么错误都能捕获，但是不建议这么用。建议是，对于特殊处理或提醒的异常需要先定义，最后定义Exception来确保程序正常运行。  </p>
<p>而且其实也不是什么错误都能捕获的。因为try本身也是代码，如果连编译都过不了的话，就无法执行try来捕获了，比如:</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>  <span class="c1"># 这里没缩进，会有缩进错误</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">NameError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;变量名或索引错误：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<p>这里Exception也无法捕获了，会抛出没有缩进的异常。  </p>
<h4 id="else-dai-ma-kuai"><a class="toclink" href="#else-dai-ma-kuai">else代码块</a></h4>
<p>在异常处理最后可以加上else代码块，只有try中的内容无异常顺利执行完之后，才会运行esle代码块中的内容：</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>  <span class="c1"># 正常不会报错</span>
<span class="k">except</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;发现未知错误&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;执行完成，未发生异常&#39;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;try1，结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>

<span class="k">try</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>  <span class="c1"># 这个会报错</span>
<span class="k">except</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;有异常，else中的内容将不会执行&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;不会执行这里&#39;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;try2，结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="s1">&#39;#&#39;</span><span class="p">))</span>
</code></pre></div>

<h4 id="finally-dai-ma-kuai"><a class="toclink" href="#finally-dai-ma-kuai">finally代码块</a></h4>
<p>无论是否有异常，最后都会执行finally代码块中的内容。如果未能捕获到异常的类型，就会抛出异常然后终止程序运行。所以在抛出异常前会先执行finally里的代码块。这是代码放在finally中和放到整个异常代码块之后的区别，就是报错前仍然会先把finally里的执行完再报错然后终止:</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">NameError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;NameError:</span><span class="si">%s</span><span class="s2">&quot;</span><span class="o">%</span><span class="n">e</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;先捕获异常，执行except&quot;</span>
          <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
          <span class="s2">&quot;然后再执行finally&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;try1，结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>

<span class="k">try</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;在抛出异常前，会先执行finally&quot;</span>
          <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span>
          <span class="s2">&quot;然后就要抛出异常了...&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;前面已经报错了，执行不到我这里&quot;</span><span class="p">)</span>
</code></pre></div>

<h4 id="xiao-jie"><a class="toclink" href="#xiao-jie">小结</a></h4>
<p>基本上所有的情况都有了，那么异常最复杂的情况大概就是下面这样，所有的都用上了:</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="c1"># 这里写上你的代码，正确的或者有错误的</span>
    <span class="k">pass</span>
<span class="k">except</span> <span class="ne">NameError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="c1"># 处理单个异常类型</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;NameError: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">IndexError</span><span class="p">,</span> <span class="ne">KeyError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="c1"># 处理多个异常类型</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;列表或字典错误：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="c1"># 处理其它异常</span>
    <span class="c1"># 在处理完已知的异常后，还是可以这么写，处理一些未预见的情况</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;未知错误：</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="c1"># try里的代码正常执行完后，会执行这里的代码</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;未发现异常&quot;</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="c1"># 无论异常与否，最后都执行这里的代码</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;异常处理完成&quot;</span><span class="p">)</span>
</code></pre></div>

<h3 id="zhu-dong-pao-chu-yi-chang-raise"><a class="toclink" href="#zhu-dong-pao-chu-yi-chang-raise">主动抛出异常(raise)</a></h3>
<p>使用raise可以主动触发一个异常。<br>
<code>raise [Exception [, args [, traceback]]]</code>：Exception是异常类型，可以是python有的其他错误类型。可以缺省，缺省的话错误类型就是None，后面的一个参数是异常的信息，也就是上面例子中我们捕获的e。最后还有一个参数可省略，是跟踪错误对象的，上课没讲也很少用的到。  </p>
<div class="highlight"><pre><span></span><code><span class="n">n</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">&quot;输入一个数字：&quot;</span><span class="p">)</span>  <span class="c1"># 如果这里输入的是非数字，回车后就会报错</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">n</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
    <span class="k">raise</span> <span class="ne">Exception</span> <span class="p">(</span><span class="s2">&quot;发现非数字&quot;</span><span class="p">)</span>
</code></pre></div>

<p><em>如果不知道要抛出那种类型的异常，那么就抛出Exception吧。这个是所有异常的基类。</em>  </p>
<p>捕获这个异常:</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">Exception</span> <span class="p">(</span><span class="s2">&quot;发现非数字&quot;</span><span class="p">)</span>  <span class="c1"># 直接把异常抛出</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span> <span class="p">(</span><span class="s2">&quot;触发自定义异常：&quot;</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<h4 id="zi-ding-yi-yi-chang"><a class="toclink" href="#zi-ding-yi-yi-chang">自定义异常</a></h4>
<p>首先异常也是类，上面的异常类型，其实都是类名。except匹配的异常类型就是匹配类名，所有的异常类型都是继承自Exception，所以可以使用Exception来捕获所有的异常。<br>
另外其实Exception是继承自BaseException，但是我们平时不需要知道BaseException的存在：</p>
<div class="highlight"><pre><span></span><code><span class="k">try</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">Exception</span> <span class="p">(</span><span class="s2">&quot;发现非数字&quot;</span><span class="p">)</span>  <span class="c1"># 直接把异常抛出</span>
<span class="k">except</span> <span class="ne">BaseException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>  <span class="c1"># 通过BaseException同样可以捕获到异常</span>
    <span class="nb">print</span> <span class="p">(</span><span class="s2">&quot;触发自定义异常：&quot;</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<p>自定义异常我们只要熟练运用类的方法就可以了。一般就是自定义继承Exception的新的异常类型，或者自定义继承自其它异常类型的子类异常类型:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">MyException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="s2">&quot;自定义新的异常类型&quot;</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span>
    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>  <span class="c1"># 这段str方法可以不写，可以从父类继承到</span>
        <span class="s2">&quot;打印类的时候，会打印这里的返回值&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span>

<span class="c1"># 主动抛出异常并捕获</span>
<span class="k">try</span><span class="p">:</span>
    <span class="k">raise</span> <span class="n">MyException</span><span class="p">(</span><span class="s1">&#39;我的异常&#39;</span><span class="p">)</span>
<span class="k">except</span> <span class="n">MyException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;这是我的异常：&quot;</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;结束&quot;</span><span class="o">.</span><span class="n">center</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">))</span>
</code></pre></div>

<p>自定义的异常，应该只是逻辑上有错误，影响你程序的正常运行但是不影响python代码的执行。所以python是不会报错的，我们要触发自己定义的异常，都是通过逻辑判断后主动将自定义的异常通过raise抛出。<br>
自定义异常类中的str方法，是不需要的，因为可以从父类继承到。这里写出来是为了说明，我们打印异常信息是通过str方法定义的。就是就是把你捕获到的异常对象通过as赋值，然后打印这个对象（打印这个对象就是调用这个对象的str方法）。当然也可以像例子中这样不继承，自己重构，自定义异常信息的处理。  </p>
<h4 id="nei-zhi-yi-chang-lei-xing"><a class="toclink" href="#nei-zhi-yi-chang-lei-xing">内置异常类型</a></h4>
<p>异常是类，所以是有继承关系的（层次结构）。<br>
异常类的层次结构：<a href="https://docs.python.org/zh-cn/dev/library/exceptions.html#exception-hierarchy">https://docs.python.org/zh-cn/dev/library/exceptions.html#exception-hierarchy</a>。<br>
这个是python标准库的文档，可以查到所有内置的异常类。  </p>
<p>Python鼓励从Exception类或它的某个子类来派生新的异常，上一节就是继承Exception类创建自定义异常。  </p>
<p>如果需要raise抛出异常，并且要有错误信息，那么就必须指定一个异常类。如果偷懒不想自定义异常类，那么就去内置异常类中找（一般找不到合适的类，因为如果有，那你不需要raise就已经抛出异常了）。如果没有合适的内置异常类，那么抛出Exception，就像raise第一个示例中用的那样。  </p>
<h3 id="duan-yan-assert"><a class="toclink" href="#duan-yan-assert">断言(assert)</a></h3>
<p>判断一个条件，为真则继续，否则抛出异常。异常类型：AssertionError：</p>
<div class="highlight"><pre><span></span><code><span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">str</span>  <span class="c1"># 没有问题，会继续往下执行</span>
<span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">int</span>  <span class="c1"># 执行后将抛出异常</span>
</code></pre></div>

<p>还能定义错误信息，加在语句最后：</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">int</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s2">&quot;&lt;pyshell#0&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
    <span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">int</span>
<span class="ne">AssertionError</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;不支持的数据类型&quot;</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s2">&quot;&lt;pyshell#1&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
    <span class="k">assert</span> <span class="nb">type</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;不支持的数据类型&quot;</span>
<span class="ne">AssertionError</span><span class="p">:</span> <span class="n">不支持的数据类型</span>
<span class="o">&gt;&gt;&gt;</span> 
</code></pre></div>

<h3 id="traceback-mo-kuai"><a class="toclink" href="#traceback-mo-kuai">traceback模块</a></h3>
<p>python中用于处理异常栈的模块是traceback模块，它提供了print_exception、format_exception等输出异常栈等常用的工具函数。<br>
traceback对象中包含出错的行数、位置等数据，所以比e里的数据更详细，很有用：</p>
<div class="highlight"><pre><span></span><code><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>  <span class="c1"># 简单的信息</span>
    <span class="kn">import</span> <span class="nn">traceback</span>
    <span class="n">error_msg</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">()</span>  <span class="c1"># 通常就是把这个error的字符串记录下来或者返回</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
</code></pre></div>

<p>如果要打印的话，可以用这个方法 traceback.print_exc() 。不过通常是先保存下来，所以一般是例子里这么用，拿到详细的异常信息的字符串，返回或者记录下来。  </p>
<h4 id="jiang-yi-chang-xin-xi-bao-cun-dao-wen-jian"><a class="toclink" href="#jiang-yi-chang-xin-xi-bao-cun-dao-wen-jian">将异常信息保存到文件</a></h4>
<p>有一个使用场景，就是放在在脚本中。调试的时候程序遇到异常，可以在终端看到错误信息。那么在程序上线后，期望是可以发生异常，捕获异常让程序可以继续运行。但是要把错误信息写到文件中，这样同样可以获取到抛出异常时的错误信息。<em>把原来输出到终端的错误信息，保存到文件中，方便之后排查问题。</em><br>
示例代码如下：</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">logging</span>

<span class="c1"># 定义日志模块，将信息保存到文件中</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span>
    <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span>
    <span class="n">filename</span><span class="o">=</span><span class="s2">&quot;error.log&quot;</span><span class="p">,</span>
    <span class="nb">format</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">%(asctime)s</span><span class="s2"> </span><span class="si">%(levelname).3s</span><span class="s2"> </span><span class="si">%(message)s</span><span class="s2">&quot;</span><span class="p">,</span>
    <span class="n">datefmt</span><span class="o">=</span><span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span><span class="p">,</span>
    <span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="sd">&quot;&quot;&quot;省了main函数的逻辑&quot;&quot;&quot;</span>
    <span class="k">pass</span>

<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="kn">import</span> <span class="nn">traceback</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">main</span><span class="p">()</span>
    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="n">error_msg</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">()</span>
        <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
</code></pre></div>

<p>这样几乎可以捕获所有的异常，并把错误消息保存到文件中，方便之后排查。<br>
<strong>注意：</strong>main函数如果有装饰器的话，装饰器是在try的代码块外的。所以如果装饰器有异常，是无法捕获到的。<br>
再定义一个函数执行并返回main函数。把这个函数放到try里，应该可以解决问题。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>